#ifndef IOREGISTER_HPP
#define IOREGISTER_HPP

#include <QMutexLocker>

#include "register.hpp"

/**
* @brief
*
* @class IORegister ioregister.hpp "ioregister.hpp"
*/
class IORegister : public Register
{
Q_OBJECT
public:
    /**
    * @brief Overloaded Constructor, sets the internal data
    *
    * @fn IORegister
    * @param address
    * @param bank
    * @param value
    * @overload IORegister(int address, int bank, int value);
    */
    explicit IORegister(int address, int bank, int standard = 0);


    /**
    * @brief Destructor
    *
    * @fn ~IORegister
    */
    ~IORegister();

    /**
    * @brief Set the Value of the allocated Tris Register
    *
    * @fn setTrisValue
    * @param value
    */
    void setTrisValue(int value);

    /**
    * @brief Get the Value of the allocated Tris Register
    *
    * @fn getTrisValue
    * @return int
    */
    int getTrisValue() const;

    /**
    * @brief Set a single bit of the allocated Tris Register
    *
    * @fn setTrisBit
    * @param bit
    */
    void setTrisBit(int bit);

    /**
    * @brief Clear a single bit of the allocated Tris Register
    *
    * @fn clearTrisBit
    * @param bit
    */
    void clearTrisBit(int bit);

    /**
    * @brief Check whether the specified bit is set in the allocated Tris Register
    *
    * @fn trisIsSet
    * @param bit
    * @return bool
    */
    bool trisIsSet(int bit) const;

    /**
    * @brief Clear the complete Tris Register
    *
    * @fn clearTris
    */
    void clearTris();

    /**
    * @brief Save the pointer to a Register as Tris
    *
    * @fn setTris
    * @param trisRegister
    */
    void setTris(Register* trisRegister);

    /**
    * @brief Set the Value
    *
    * @fn setValue
    * @param value
    */
    void setValue(int value, bool force);

    /**
    * @brief Set a single bit
    *
    * @fn setBit
    * @param bit
    */
    void setBit(int bit);

    /**
    * @brief Clear a single bit
    *
    * @fn clearBit
    * @param bit
    */
    void clearBit(int bit);

    /**
    * @brief Clear the complete content
    *
    * @fn clear
    */
    void clear();

    /**
    * @brief Set a bit as an input bit
    *
    * @fn setInput
    * @param bit
    */
    void setInput(int bit);

    /**
    * @brief Set a bit as an output bit
    *
    * @fn setOutput
    * @param bit
    */
    void setOutput(int bit);

    /**
    * @brief Convert the allocated Tris register to a String
    *
    * @fn trisToString
    * @param bit
    * @return QString
    */
    QString trisToString(int bit = -1) const;

    /**
    * @brief Convert the allocated Latch Register to a String
    *
    * @fn latchToString
    * @param bit
    * @return QString
    */
    QString latchToString(int bit = -1) const;

    void reset();

private:
    bool latchIsSet(int bit) const;
    bool isInput(int bit) const;
    void setLatchValue(int value);
    int getLatchValue() const;
    void setLatchBit(int bit);
    bool getLatchBit(int bit) const;
    void clearLatchBit(int bit);
    void clearLatch();

    Register *tris;
    Register *latch;

private slots:
    /**
    * @brief Update the output according to the Tris Register
    * @details Save old output pins to Latch if they are converted to input pins
    * Restore Latch values if input pin is converted to output pin
    * This slot is called when the allocated Tris Register has been changed outside
    *
    * @fn updateOutput
    * @param oldValue
    */
    void updateOutput(int oldValue);

};

#endif // IOREGISTER_HPP
